package com.jdy.haoduoaiteacher.util;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import android.widget.ImageView;

import com.jdy.haoduoaiteacher.view.CircularImageView;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ImageLoader {

  private final MemoryCache memoryCache = new MemoryCache();
  private final AbstractFileCache fileCache;
  private final Map<ImageView, String> imageViews = Collections
      .synchronizedMap(new WeakHashMap<ImageView, String>());
  // �̳߳�
  private final ExecutorService executorService;

  public ImageLoader(Context context) {
    fileCache = new FileCache(context);
    executorService = Executors.newFixedThreadPool(50);
  }

  // ����Ҫ�ķ���
  public void DisplayImage(String url, ImageView imageView,
      boolean isLoadOnlyFromCache) {
    imageViews.put(imageView, url);
    // �ȴ��ڴ滺���в���

    Bitmap bitmap = memoryCache.get(url);
    if (bitmap != null)
      imageView.setImageBitmap(bitmap);
    else if (!isLoadOnlyFromCache) {

      // ��û�еĻ��������̼߳���ͼƬ
      queuePhoto(url, imageView);
    }
  }

  public void DisplayImage(String url, CircularImageView imageView,
      boolean isLoadOnlyFromCache) {
    imageViews.put(imageView, url);
    // �ȴ��ڴ滺���в���

    Bitmap bitmap = memoryCache.get(url);
    if (bitmap != null)
      imageView.setImageBitmap(bitmap);
    else if (!isLoadOnlyFromCache) {

      // ��û�еĻ��������̼߳���ͼƬ
      queuePhoto(url, imageView);
    }
  }

  private void queuePhoto(String url, ImageView imageView) {
    PhotoToLoad p = new PhotoToLoad(url, imageView);
    executorService.submit(new PhotosLoader(p));
  }

  private Bitmap getBitmap(String url) {
    File f = fileCache.getFile(url);

    // �ȴ��ļ������в����Ƿ���
    Bitmap b = null;
    if (f != null && f.exists()) {
      b = decodeFile(f);
    }
    if (b != null) {
      return b;
    }
    // ����ָ����url������ͼƬ
    try {
      Bitmap bitmap = null;
      URL imageUrl = new URL(URLEncoder.encode(url).replace("%3A", ":")
          .replace("%2F", "/"));
      HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection();
      conn.setConnectTimeout(30000);
      conn.setReadTimeout(30000);
      conn.setInstanceFollowRedirects(true);
      InputStream is = conn.getInputStream();
      OutputStream os = new FileOutputStream(f);
      CopyStream(is, os);
      os.close();
      bitmap = decodeFile(f);

      // bitmap = BitmapFactory.decodeStream(is);
      return bitmap;
    } catch (Exception ex) {
      Log.e("", "getBitmap catch Exception...\nmessage = " + ex.getMessage());
      return null;
    }
  }

  // decode���ͼƬ���Ұ����������Լ����ڴ���ģ�������ÿ��ͼƬ�Ļ����СҲ�������Ƶ�
  private Bitmap decodeFile(File f) {
    try {
      // decode image size
      BitmapFactory.Options o = new BitmapFactory.Options();
      o.inJustDecodeBounds = true;
      BitmapFactory.decodeStream(new FileInputStream(f), null, o);

      // Find the correct scale value. It should be the power of 2.
      final int REQUIRED_SIZE = 100;
      int width_tmp = o.outWidth, height_tmp = o.outHeight;
      int scale = 1;
      while (true) {
        if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE)
          break;
        width_tmp /= 2;
        height_tmp /= 2;
        scale *= 2;
      }

      // decode with inSampleSize
      BitmapFactory.Options o2 = new BitmapFactory.Options();
      o2.inSampleSize = scale;
      return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
    } catch (FileNotFoundException e) {
    }
    return null;
  }

  // Task for the queue
  private class PhotoToLoad {
    public String url;
    public ImageView imageView;

    public PhotoToLoad(String u, ImageView i) {
      url = u;
      imageView = i;
    }
  }

  class PhotosLoader implements Runnable {
    PhotoToLoad photoToLoad;

    PhotosLoader(PhotoToLoad photoToLoad) {
      this.photoToLoad = photoToLoad;
    }

    @Override
    public void run() {
      if (imageViewReused(photoToLoad))
        return;
      Bitmap bmp = getBitmap(photoToLoad.url);
      memoryCache.put(photoToLoad.url, bmp);
      if (imageViewReused(photoToLoad))
        return;
      BitmapDisplayer bd = new BitmapDisplayer(bmp, photoToLoad);
      // ���µĲ�������UI�߳���
      Activity a = (Activity) photoToLoad.imageView.getContext();
      a.runOnUiThread(bd);
    }
  }

  /**
   * ��ֹͼƬ��λ
   * 
   * @param photoToLoad
   * @return
   */
  boolean imageViewReused(PhotoToLoad photoToLoad) {
    String tag = imageViews.get(photoToLoad.imageView);
    if (tag == null || !tag.equals(photoToLoad.url))
      return true;
    return false;
  }

  // ������UI�߳��и��½���
  class BitmapDisplayer implements Runnable {
    Bitmap bitmap;
    PhotoToLoad photoToLoad;

    public BitmapDisplayer(Bitmap b, PhotoToLoad p) {
      bitmap = b;
      photoToLoad = p;
    }

    @Override
    public void run() {
      if (imageViewReused(photoToLoad))
        return;
      if (bitmap != null)
        photoToLoad.imageView.setImageBitmap(bitmap);

    }
  }

  // public void clearCache() {
  // memoryCache.clear();
  // fileCache.clear();
  // }

  public static void CopyStream(InputStream is, OutputStream os) {
    final int buffer_size = 1024;
    try {
      byte[] bytes = new byte[buffer_size];
      for (;;) {
        int count = is.read(bytes, 0, buffer_size);
        if (count == -1)
          break;
        os.write(bytes, 0, count);
      }
    } catch (Exception ex) {
      Log.e("", "CopyStream catch Exception...");
    }
  }
}